package pers.kw.filter;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import pers.kw.config.properties.IgnoreWhiteProperties;
import pers.kw.config.properties.OAuthConfigProperties;
import pers.kw.contants.TokenConstants;
import pers.kw.entity.TokenDto;
import pers.kw.protocol.ExceptionResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * 全局过滤器
 */
@Slf4j
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Resource
    private IgnoreWhiteProperties ignoreWhite;

    @Resource
    private OAuthConfigProperties oAuthConfigProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest.Builder mutate = request.mutate();
        String path = request.getURI().getPath();
        log.info("请求路径：{}", path);
        //todo 请求参数打印

        //白名单放行
        if (!CollectionUtils.isEmpty(ignoreWhite.getWhites())
                && ignoreWhite.getWhites().contains(path)) {
            return chain.filter(exchange);
        }

        /*String token = this.getToken(request);
        //令牌不能为空
        if (StringUtils.isBlank(token)) {
            return webFluxResponseWriter(response, "非法请求，无token令牌", HttpStatus.FORBIDDEN.value());
        }

        //秘钥验证令牌是否合法
        //--token生成时使用的密钥对的公钥
        SignatureVerifier signatureVerifier = new RsaVerifier(
                oAuthConfigProperties.getOauthToken().getVerifierKey()
        );
        Jwt jwt;
        try {
            jwt = JwtHelper.decodeAndVerify(token, signatureVerifier);
        } catch (Exception e) {
            log.error("token错误", e);
            return webFluxResponseWriter(response, "token错误", HttpStatus.FORBIDDEN.value());
        }
        String claims = jwt.getClaims();
        TokenDto tokenDto = JSON.parseObject(claims, TokenDto.class);
        //解析token
        //通过redis验证有效期
        //token redis中的值校验，登录信息是否已被移除

        //ToDo body参数加密解密处理*/

        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }

    public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String msg, int code) {
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        ExceptionResponse result = ExceptionResponse.fail(code, msg);
        DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
        return response.writeWith(Mono.just(dataBuffer));
    }

    /**
     * 获取请求头的认证信息
     */
    private String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
        // 如果前端设置了令牌前缀，则裁剪掉前缀
        if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
            token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
        }
        return token;
    }

    @Override
    public int getOrder() {
        return -200;
    }
}
